package com.lanchetech.admin.service.impl;


import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.util.CollectionUtils;
import com.alibaba.fastjson.JSON;
import com.baidu.fsg.uid.UidGenerator;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.lanchetech.admin.service.OrderService;
import com.lanchetech.admin.service.VipService;
import com.lanchetech.bean.dto.OrderExcelDTO;
import com.lanchetech.bean.request.CountByTimeReq;
import com.lanchetech.bean.request.OrderAddressPageReq;
import com.lanchetech.bean.request.OrderPageReq;
import com.lanchetech.bean.request.OrderPayReq;
import com.lanchetech.bean.response.*;
import com.lanchetech.bean.strategy.OrderMergeStrategy;
import com.lanchetech.bean.util.PageHelpUtil;
import com.lanchetech.bean.vo.*;
import com.lanchetech.common.enums.*;
import com.lanchetech.dao.*;
import com.lanchetech.entity.*;
import com.lanchetech.service.*;
import com.raycloud.open.sdk.api.request.KdzsPrintTradeRefundRequest;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@Service
public class OrderServiceImpl implements OrderService {

    private final Logger log = LoggerFactory.getLogger(this.getClass());

    @Autowired
    OrdersMapper ordersMapper;

    @Autowired
    OrderSkuMapper orderSkuMapper;

    @Autowired
    SpuMapper spuMapper;

    @Autowired
    SkuMapper skuMapper;

    @Autowired
    OrderAddressMapper orderAddressMapper;

    @Autowired
    OrderDiscountMapper orderDiscountMapper;

    @Autowired
    AfterSaleMapper afterSaleMapper;

    @Autowired
    WxPayService wxPayService;

    @Autowired
    UserCommissionMapper userCommissionMapper;

    @Value("${domain.url}")
    private String domainUrl;

    @Resource
    UidGenerator uidGenerator;

    @Autowired
    ColumnCourseAuthMapper columnCourseAuthMapper;

    @Autowired
    ConsumptionService consumptionService;

    @Autowired
    CommissionRecordMapper commissionRecordMapper;

    @Autowired
    UserMapper userMapper;

    @Autowired
    HipoConfigMapper hipoConfigMapper;

    @Autowired
    IdentityMapper identityMapper;

    @Autowired
    VipService vipService;

    @Autowired
    CardFlowMapper cardFlowMapper;

    @Autowired
    RewardQueueMapper rewardQueueMapper;

    @Autowired
    BonusCountMapper bonusCountMapper;

    @Autowired
    DaoService daoService;

    @Autowired
    UserVoucherMapper userVoucherMapper;

    @Autowired
    OrderPayMapper orderPayMapper;

    @Autowired
    ShopMapper shopMapper;

    @Autowired
    LogisticsService logisticsService;

    @Value("${wx.pay.appId}")
    private String miniAppId;

    @Value("${wx.app.appId}")
    private String appAppId;

    @Autowired
    TenantMapper tenantMapper;

    @Autowired
    TenantFlowMapper tenantFlowMapper;

    @Autowired
    FinanceService financeService;

    @Autowired
    KuaidizsService kuaidizsService;

    @Autowired
    InviteFirstBuyMapper inviteFirstBuyMapper;

    @Autowired
    PerformanceAmountMapper performanceAmountMapper;

    @Autowired
    CommissionService commissionService;

    @Autowired
    CouponMapper couponMapper;

    @Autowired
    DividendPrecipitationMapper dividendPrecipitationMapper;

    @Autowired
    GroupsPerformanceMapper groupsPerformanceMapper;

    @Autowired
    ShareholderPerformanceMapper shareholderPerformanceMapper;

    @Autowired
    CommonOrderService commonOrderService;

    @Override
    public ResultData<BasePageResp<OrderResp>> getOrderPage(OrderPageReq req) {
        Page page = null;
        List<Long> orderIds = new ArrayList<>();
        List<OrderResp> orderList = new ArrayList<>();
        boolean isSkuSearch = req.getSkuId() != null || !StringUtils.isEmpty(req.getName());
        boolean isUserSearch = !StringUtils.isEmpty(req.getPhone()) || !StringUtils.isEmpty(req.getUserName());

        // 根据skuId或商品名称搜索
        if (isSkuSearch) {
            page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
            orderIds = orderSkuMapper.findAllBySkuIdAndName(req);
        }

        // 手机号或姓名搜索
        if (isUserSearch && !isSkuSearch) {
            OrderAddressPageReq orderAddressPageReq = new OrderAddressPageReq(req.getPageNo(), req.getPageSize(), req.getPhone(), req.getUserName());
            page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
            List<OrderAddress> orderAddressList = orderAddressMapper.findAllByPhoneAndName(orderAddressPageReq);
            orderIds = orderAddressList.stream().map(item -> item.getOrderId()).collect(Collectors.toList());
        }

        // 默认搜索
        if (!isUserSearch && !isSkuSearch) {
            page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
            orderList = ordersMapper.findAllBackPage(req);
            orderIds = orderList.stream().map(item -> item.getId()).collect(Collectors.toList());
        } else {
            if (!CollectionUtils.isEmpty(orderIds)) {
                req.setIds(orderIds);
                orderList = ordersMapper.findAllBackPage(req);
            }
        }

        // 如果没有数据，直接返回
        if (CollectionUtils.isEmpty(orderList)) {
            return PageHelpUtil.buildPage(orderList, page);
        }

        // 获取订单商品明细列表
        List<OrderSkuVO> orderSkuList = orderSkuMapper.findAllByOrderIds(orderIds);
        List<Long> skuIds = new ArrayList<>();
        List<Long> shopIds = new ArrayList<>();
        orderSkuList.forEach(item -> {
            if (!skuIds.contains(item.getSkuId())) {
                skuIds.add(item.getSkuId());
            }
            if (!shopIds.contains(item.getShopId())) {
                shopIds.add(item.getShopId());
            }
        });

        Map<Long, List<OrderSkuVO>> orderSkuMap = new HashMap<>();

        // 获取商品sku信息
        List<Sku> skuList = skuMapper.findAllByIds(skuIds);
        Map<Long, Sku> skuMap = new HashMap<>();
        skuList.stream().forEach(item -> skuMap.put(item.getId(), item));

        // 获取收货地址
        List<OrderAddress> orderAddressList = orderAddressMapper.findAllByOrderIds(orderIds);
        Map<Long, OrderAddress> orderAddressMap = new HashMap<>();
        orderAddressList.stream().forEach(item -> orderAddressMap.put(item.getOrderId(), item));

        Map<Long, User> userMap = daoService.getUserMap(orderList.stream().map(Orders::getUserId).collect(Collectors.toList()));
        Map<Long, Shop> shopMap = shopIds.isEmpty() ? new HashMap<>() : daoService.getShopMap(shopIds);
        Map<Long, Shop> tenantMap = daoService.getShopMap(orderList.stream().map(Orders::getTenantId).collect(Collectors.toList()));

        // 组装数据
        orderSkuList.stream().forEach((item) -> {
            item.setImage(skuMap.get(item.getSkuId()).getImage());
            item.setSpecNames(skuMap.get(item.getSkuId()).getSpecNames());
            item.setSpecValues(skuMap.get(item.getSkuId()).getSpecValues());
            item.setStockUnit(skuMap.get(item.getSkuId()).getStockUnit());
            if (orderSkuMap.containsKey(item.getOrderId())) {
                orderSkuMap.get(item.getOrderId()).add(item);
            } else {
                List<OrderSkuVO> list = new ArrayList<>();
                list.add(item);
                orderSkuMap.put(item.getOrderId(), list);
            }
        });
        orderList.stream().forEach(item -> {
            item.setOrderSkuList(orderSkuMap.get(item.getId()));
            item.setOrderAddress(orderAddressMap.get(item.getId()));
            item.setUserNickname(userMap.get(item.getUserId()).getNickname());
            item.setUserAvatar(userMap.get(item.getUserId()).getAvatar());
            if (item.getShopId() != null) {
                item.setShopName(shopMap.get(item.getShopId()).getShopName());
                item.setShopAvatar(shopMap.get(item.getShopId()).getAvatar());
            }
            item.setTenantNickname(tenantMap.get(item.getTenantId()).getShopName());
            item.setTenantAvatar(tenantMap.get(item.getTenantId()).getAvatar());
        });

        return PageHelpUtil.buildPage(orderList, page);
    }

    @Override
    public ResultData<OrderDataStatisticsVO> getOrderStatistics(OrderPageReq req) {
        return new ResultData<>(ordersMapper.getOrderDataStatistics(req));
    }

    /**
     * 商品订单列表导出数据
     * 目的：商家可以导出订单列表，发给供货商，要求供货商发货。供货商发货后，填写发货的快递公司、快递单号。商家可以上传并批量发货。
     * 需要的字段： orderId, 支付的总金额, spuId, skuId, 商品名称，数量，收货地址，姓名，手机号，应该
     *
     * @param req
     * @param response
     * @throws IOException
     */
    @Override
    public void exportOrderExcel(OrderPageReq req, HttpServletResponse response) throws IOException {
        ResultData<BasePageResp<OrderResp>> resp = getOrderPage(req);
        // 展开数据
        List<OrderExcelDTO> orderExcelDTOS = new ArrayList<>();
        List<Integer> orderSkuCountList = new ArrayList<>();
        boolean isEmptyIds = CollectionUtils.isEmpty(req.getCheckedIds());
        resp.getValue().getData().stream().forEach(item -> {
            // 被过滤的数量
            AtomicInteger filterCount = new AtomicInteger();
            item.getOrderSkuList().forEach(each -> {
                // 过滤未勾选的orderSku
                if (isEmptyIds || req.getCheckedIds().contains(each.getId())) {
                    orderExcelDTOS.add(OrderExcelDTO.builder()
                            .tradeNo(item.getTradeNo())
                            .spuId(each.getSpuId())
                            .skuId(each.getSkuId())
                            .totalPayAmount(item.getTotalPayAmount())
                            .productName(each.getProductName())
                            .specValues(each.getSpecValues())
                            .price(each.getPrice())
                            .count(each.getCount())
                            .stockUnit(each.getStockUnit())
                            .payTime(item.getPayTime())
                            .address(item.getOrderAddress() == null ? "" : item.getOrderAddress().getMergerName() + "," + item.getOrderAddress().getAddress())
                            .name(item.getOrderAddress() == null ? item.getName() : item.getOrderAddress().getName())
                            .phone(item.getOrderAddress() == null ? item.getPhone() : item.getOrderAddress().getPhone())
                            .userMessage(item.getUserMessage())
                            .remark(item.getRemark())
                            .status(OrdersStatusEnum.getRemarkByStatus(item.getStatus()))
                            .logisticsStatus(LogisticsStatusEnum.getRemarkByStatus(item.getLogisticsStatus()))
                            .createdAt(item.getCreatedAt())
                            .activityType(ActivityEnum.getRemarkByActivity(each.getActivityType()))
                            .activityId(each.getActivityId())
                            .shopId(item.getShopId())
                            .shopName(item.getShopName())
                            .appointmentTime(each.getAppointmentTime())
                            .verifyTime(each.getVerifyTime())
                            .verifyStatus(each.getVerifyStatus().equals((byte) 1) ? "已核销" : "未核销")
                            .build());
                } else {
                    filterCount.getAndIncrement();
                }
            });
            int count = item.getOrderSkuList().size() - filterCount.get();
            if (count > 0) {
                orderSkuCountList.add(count);
            }
        });

        String fileName = new String(("商品订单列表导出数据.xlsx").getBytes(), "UTF-8");
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName);
        OrderMergeStrategy orderMergeStrategy = new OrderMergeStrategy(orderSkuCountList);
        EasyExcel.write(response.getOutputStream(), OrderExcelDTO.class).registerWriteHandler(orderMergeStrategy).sheet("商品订单列表导出数据").doWrite(orderExcelDTOS);
    }


    @Override
    public ResultData<OrderResp> getOrderDetail(Long id) {
        Orders orders = ordersMapper.selectByPrimaryKey(id);
        OrderResp orderResp = new OrderResp();
        BeanUtils.copyProperties(orders, orderResp);

        User user = userMapper.selectByPrimaryKey(orders.getUserId());
        orderResp.setUserNickname(user.getNickname());
        orderResp.setUsername(user.getUsername());

        // 获取商品信息
        List<OrderSkuVO> orderSkuList = orderSkuMapper.findAllByOrderId(orders.getId());
        List<Long> spuIds = new ArrayList<>();
        List<Long> skuIds = new ArrayList<>();
        List<Long> afterSaleIds = new ArrayList<>();
        orderSkuList.forEach(item -> {
            if (!spuIds.contains(item.getSpuId())) {
                spuIds.add(item.getSpuId());
            }
            if (!skuIds.contains(item.getSkuId())) {
                skuIds.add(item.getSkuId());
            }
            if (item.getAfterSaleId() != null) {
                afterSaleIds.add(item.getAfterSaleId());
            }
        });

        // 获取商品sku信息
        List<Sku> skuList = skuMapper.findAllByIds(skuIds);
        Map<Long, Sku> skuMap = new HashMap<>();
        skuList.stream().forEach(item -> skuMap.put(item.getId(), item));

        // 获取售后信息
        Map<Long, AfterSale> afterSaleMap = new HashMap<>();
        if (afterSaleIds.size() > 0) {
            List<AfterSale> afterSaleList = afterSaleMapper.findAllByIds(afterSaleIds);
            afterSaleList.stream().forEach(item -> afterSaleMap.put(item.getId(), item));
        }

        // 组装数据
        orderSkuList.stream().forEach((item) -> {
            item.setImage(skuMap.get(item.getSkuId()).getImage());
            item.setSpecNames(skuMap.get(item.getSkuId()).getSpecNames());
            item.setSpecValues(skuMap.get(item.getSkuId()).getSpecValues());
            item.setStockUnit(skuMap.get(item.getSkuId()).getStockUnit());
            if (item.getAfterSaleId() != null) {
                item.setAfterSaleStatus(afterSaleMap.get(item.getAfterSaleId()).getStatus());
                item.setAfterSaleCount(afterSaleMap.get(item.getAfterSaleId()).getCount());
            }
        });

        orderResp.setOrderSkuList(orderSkuList);
        orderResp.setOrderAddress(orderAddressMapper.findOneByOrderId(orders.getId()));
        orderResp.setOrderDiscountList(orderDiscountMapper.findAllByOrderId(orders.getId()));

        Shop shop = shopMapper.selectByPrimaryKey(orders.getTenantId());
        orderResp.setTenantAvatar(shop.getAvatar());
        orderResp.setTenantNickname(shop.getShopName());

        //获取优惠券信息
        OrderDiscount orderDiscount = orderDiscountMapper.findOneByOrderIdAndType(id, PromotionEnum.COUPON.getPromotion());
        if (orderDiscount != null) {
            orderResp.setCoupon(couponMapper.selectByPrimaryKey(orderDiscount.getRelateId()));
        }
        return new ResultData<>(orderResp);
    }

    @Override
    public BaseResp editOrderLogistics(Orders orders) {
        orders.setLogisticsStatus(LogisticsStatusEnum.DONE.getStatus());
        ordersMapper.updateOrderLogistics(orders);
        orderSkuMapper.updateLogisticsStatusByOrderId(LogisticsStatusEnum.DONE.getStatus(), orders.getId());

        //发货解冻
        Orders selectOrder = ordersMapper.selectByPrimaryKey(orders.getId());
        logisticsService.unFreezeOrder(selectOrder);
        return new BaseResp();
    }

    @Override
    public BaseResp editOrderRemark(Orders orders) {
        ordersMapper.updateRemarkById(orders);
        return new BaseResp();
    }

    @Override
    public String refundNotify(String xmlData) {
        wxPayService.getConfig().setAppId(xmlData.indexOf(miniAppId) > -1 ? miniAppId : appAppId);
        wxPayService.getConfig().setTradeType(xmlData.indexOf(miniAppId) > -1 ? "JSAPI" : "APP");

        WxPayRefundNotifyResult wxPayRefundNotifyResult;
        try {
            wxPayRefundNotifyResult = wxPayService.parseRefundNotifyResult(xmlData);
            // 检查微信退款成功的回调是否是他人伪造
            wxPayRefundNotifyResult.checkResult(wxPayService, "MD5", true);
        } catch (WxPayException e) {
            log.error("主动关闭订单-退款失败，失败信息:{}", e);
            return WxPayNotifyResponse.fail("退款失败");
        }

        //判断返回状态信息是否正确，是否真的退款了
        if ("SUCCESS".equals(wxPayRefundNotifyResult.getReturnCode())) {
            WxPayRefundNotifyResult.ReqInfo reqInfo = wxPayRefundNotifyResult.getReqInfo();
            //判断退款状态
            if ("SUCCESS".equals(reqInfo.getRefundStatus())) {
                String refundNo = reqInfo.getOutRefundNo();
                commonOrderService.refundNotifyComplete(refundNo);

                return WxPayNotifyResponse.success("退款成功！");
            }
        }
        return WxPayNotifyResponse.fail("回调有误!");
    }

    @Override
    public ResultData<BasePageResp<OrderPayVO>> getAnotherPayOrderPage(OrderPayReq req) {
        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        List<OrderPayVO> list = orderPayMapper.findAllPage(req);
        if (!list.isEmpty()) {
            List<Long> orderIds = list.stream().map(OrderPayVO::getOrderId).collect(Collectors.toList());

            List<Long> userIds = list.stream().map(OrderPayVO::getOrderUserId).collect(Collectors.toList());
            List<Long> payUserIds = list.stream().map(OrderPayVO::getPayUserId).collect(Collectors.toList());
            userIds.addAll(payUserIds);

            Map<Long, User> userMap = daoService.getUserMap(userIds);
            Map<Long, Orders> ordersMap = daoService.getOrdersMap(orderIds);

            list.stream().forEach(item -> {
                item.setPayUserNickname(userMap.get(item.getPayUserId()).getNickname());
                item.setPayUserAvatar(userMap.get(item.getPayUserId()).getAvatar());
                item.setOrderUserNickname(userMap.get(item.getOrderUserId()).getNickname());
                item.setOrderUserAvatar(userMap.get(item.getOrderUserId()).getAvatar());

                item.setOrderTotalAmount(ordersMap.get(item.getOrderId()).getTotalPayAmount());
                item.setRefundAmount(ordersMap.get(item.getOrderId()).getTotalRefundAmount());
            });
        }
        return PageHelpUtil.buildPage(list, page);
    }

    @Override
    public ResultData<List<LongCountByDateVO>> getOrdersCount(CountByTimeReq req) {
        return new ResultData<>(ordersMapper.getOrdersCount(req));
    }

    @Override
    public ResultData<List<BigDecimalCountByDateVO>> getPayAmountCount(CountByTimeReq req) {
        return new ResultData<>(ordersMapper.getPayAmountCount(req));
    }
}